package com.test.demo1.common;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RScript;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;
@Component
@Slf4j
public class RedissonSegmentedInventorySystem {

    // Redis配置
    private static final int SEGMENTS = 10; // 库存分段数量

    private static final int THREAD_COUNT = 50; // 并发线程数
    private static final int REQUESTS_PER_THREAD = 20; // 每个线程请求次数

    private  final RedissonClient redisson;

    public RedissonSegmentedInventorySystem(RedissonClient redisson) {
        this.redisson = redisson;
    }


    // 初始化分段库存
    public void initializeInventory(int TOTAL_INVENTORY) {
        int baseStock = TOTAL_INVENTORY / SEGMENTS;
        int remainder = TOTAL_INVENTORY % SEGMENTS;

        for (int i = 0; i < SEGMENTS; i++) {
            int segmentStock = baseStock + (i < remainder ? 1 : 0);
            RAtomicLong atomicLong = redisson.getAtomicLong("inventory_segment_" + i);
            atomicLong.set(segmentStock);
        }
    }

    // 使用Lua脚本扣减库存（推荐）
    public boolean deductInventoryWithLua(int quantity) {
        if (quantity <= 0) return false;

        // 随机选择起始分段
        int startSegment = ThreadLocalRandom.current().nextInt(SEGMENTS);

        for (int i = 0; i < SEGMENTS; i++) {
            int segment = (startSegment + i) % SEGMENTS;
            String key = "inventory_segment_" + segment;

            // Lua脚本：原子操作扣减库存
            String script =
                    "local current = redis.call('get', KEYS[1]); " +
                            "if current and tonumber(current) >= tonumber(ARGV[1]) then " +
                            "   redis.call('decrby', KEYS[1], ARGV[1]); " +
                            "   return 1; " +
                            "else " +
                            "   return 0; " +
                            "end";

            Long result = redisson.getScript().eval(RScript.Mode.READ_WRITE,
                    script, RScript.ReturnType.INTEGER, Collections.singletonList(key), quantity);

            if (result == 1) {
                return true; // 扣减成功
            }
        }
        return false; // 所有分段尝试失败
    }

    // 使用分布式锁扣减库存
    public boolean deductInventoryWithLock(int quantity) {
        if (quantity <= 0) return false;

        // 随机选择起始分段
        int startSegment = ThreadLocalRandom.current().nextInt(SEGMENTS);

        for (int i = 0; i < SEGMENTS; i++) {
            int segment = (startSegment + i) % SEGMENTS;
            String key = "inventory_segment_" + segment;
            RLock lock = redisson.getLock("lock:" + key);

            try {
                // 尝试获取锁，最多等待100ms，锁持有时间10s
                if (lock.tryLock(100, 10000, TimeUnit.MILLISECONDS)) {
                    try {
                        RAtomicLong atomicLong = redisson.getAtomicLong(key);
                        long current = atomicLong.get();
                        if (current >= quantity) {
                            atomicLong.addAndGet(-quantity);
                            return true;
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        return false;
    }

    // 模拟高并发请求
    public void simulateHighConcurrency(boolean useLua) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
        CountDownLatch latch = new CountDownLatch(THREAD_COUNT * REQUESTS_PER_THREAD);
        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger failureCount = new AtomicInteger(0);

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < THREAD_COUNT; i++) {
            executor.submit(() -> {
                for (int j = 0; j < REQUESTS_PER_THREAD; j++) {
                    int quantity = ThreadLocalRandom.current().nextInt(1, 5);
                    boolean success;

                    if (useLua) {
                        success = deductInventoryWithLua(quantity);
                    } else {
                        success = deductInventoryWithLock(quantity);
                    }

                    if (success) {
                        successCount.incrementAndGet();
                    } else {
                        failureCount.incrementAndGet();
                    }
                    latch.countDown();
                }
            });
        }

        latch.await();
        executor.shutdown();

        long endTime = System.currentTimeMillis();

        // 打印结果
        log.info("==============================================");
        log.info("并发模拟完成 (" + (useLua ? "Lua脚本" : "分布式锁") + "方式)");
        log.info("总请求数: " + (THREAD_COUNT * REQUESTS_PER_THREAD));
        log.info("成功扣减次数: " + successCount.get());
        log.info("失败次数: " + failureCount.get());
        log.info("总耗时: " + (endTime - startTime) + "ms");
        log.info("吞吐量: " +
                (THREAD_COUNT * REQUESTS_PER_THREAD) / ((endTime - startTime) / 1000.0) + " req/s");

        // 打印剩余库存
        printRemainingInventory();
    }

    // 打印剩余库存
    private void printRemainingInventory() {
        int totalRemaining = 0;
        log.info("\n分段库存剩余:");
        for (int i = 0; i < SEGMENTS; i++) {
            RAtomicLong atomicLong = redisson.getAtomicLong("inventory_segment_" + i);
            long stock = atomicLong.get();
            totalRemaining += stock;
            log.info("Segment " + i + ": " + stock);
        }
        log.info("总剩余库存: " + totalRemaining);
    }

    // 关闭Redisson客户端
    public void shutdown() {
        if (redisson != null && !redisson.isShutdown()) {
            redisson.shutdown();
        }
    }

//    public static void main(String[] args) {
//        RedissonSegmentedInventorySystem system = new RedissonSegmentedInventorySystem();
//
//        try {
//            // 初始化库存
//            system.initializeInventory();
//            log.info("库存初始化完成，总库存: " + TOTAL_INVENTORY);
//
//            // 使用Lua脚本方式测试
//            log.info("\n===== 使用Lua脚本方式测试 =====");
//            system.simulateHighConcurrency(true);
//
//            // 重新初始化库存
//            system.initializeInventory();
//
//            // 使用分布式锁方式测试
//            log.info("\n===== 使用分布式锁方式测试 =====");
//            system.simulateHighConcurrency(false);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        } finally {
//            system.shutdown();
//        }
//    }

    // 原子计数类
    static class AtomicInteger {
        private int value;

        public AtomicInteger(int initial) {
            value = initial;
        }

        public synchronized int incrementAndGet() {
            return ++value;
        }

        public synchronized int get() {
            return value;
        }
    }
}
